stream.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright (c) 2009-2016 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_STRINGSTREAM_BASED_CONVERTER_HPP
  5. #define BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP
  6. #include <boost/convert/parameters.hpp>
  7. #include <boost/convert/detail/is_string.hpp>
  8. #include <boost/make_default.hpp>
  9. #include <boost/noncopyable.hpp>
  10. #include <sstream>
  11. #include <iomanip>
  12. #define BOOST_CNV_STRING_ENABLE \
  13. template<typename string_type, typename type> \
  14. typename boost::enable_if<cnv::is_string<string_type>, void>::type \
  15. operator()
  16. #define BOOST_CNV_PARAM(PARAM_NAME, PARAM_TYPE) \
  17. this_type& \
  18. operator()(boost::parameter::aux::tag<boost::cnv::parameter::type::PARAM_NAME, PARAM_TYPE const>::type const& arg)
  19. namespace boost { namespace cnv
  20. {
  21. template<class Char> struct basic_stream;
  22. using cstream = boost::cnv::basic_stream<char>;
  23. using wstream = boost::cnv::basic_stream<wchar_t>;
  24. }}
  25. template<class Char>
  26. struct boost::cnv::basic_stream : boost::noncopyable
  27. {
  28. // C01. In string-to-type conversions the "string" must be a CONTIGUOUS ARRAY of
  29. // characters because "ibuffer_type" uses/relies on that (it deals with char_type*).
  30. // C02. Use the provided "string_in" as the input (read-from) buffer and, consequently,
  31. // avoid the overhead associated with stream_.str(string_in) --
  32. // copying of the content into internal buffer.
  33. // C03. The "strbuf.gptr() != strbuf.egptr()" check replaces "istream.eof() != true"
  34. // which for some reason does not work when we try converting the "true" string
  35. // to "bool" with std::boolalpha set. Seems that istream state gets unsynced compared
  36. // to the actual underlying buffer.
  37. using char_type = Char;
  38. using this_type = boost::cnv::basic_stream<char_type>;
  39. using stream_type = std::basic_stringstream<char_type>;
  40. using istream_type = std::basic_istream<char_type>;
  41. using buffer_type = std::basic_streambuf<char_type>;
  42. using stdstr_type = std::basic_string<char_type>;
  43. using manipulator_type = std::ios_base& (*)(std::ios_base&);
  44. struct ibuffer_type : buffer_type
  45. {
  46. using buffer_type::eback;
  47. using buffer_type::gptr;
  48. using buffer_type::egptr;
  49. ibuffer_type(char_type const* beg, std::size_t sz) //C01
  50. {
  51. char_type* b = const_cast<char_type*>(beg);
  52. buffer_type::setg(b, b, b + sz);
  53. }
  54. };
  55. struct obuffer_type : buffer_type
  56. {
  57. using buffer_type::pbase;
  58. using buffer_type::pptr;
  59. using buffer_type::epptr;
  60. };
  61. basic_stream() : stream_(std::ios_base::in | std::ios_base::out) {}
  62. #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
  63. basic_stream(this_type&& other) : stream_(std::move(other.stream_)) {}
  64. #endif
  65. BOOST_CNV_STRING_ENABLE(type const& v, optional<string_type>& s) const { to_str(v, s); }
  66. BOOST_CNV_STRING_ENABLE(string_type const& s, optional<type>& r) const { str_to(cnv::range<string_type const>(s), r); }
  67. // Resolve ambiguity of string-to-string
  68. template<typename type> void operator()( char_type const* s, optional<type>& r) const { str_to(cnv::range< char_type const*>(s), r); }
  69. template<typename type> void operator()(stdstr_type const& s, optional<type>& r) const { str_to(cnv::range<stdstr_type const>(s), r); }
  70. // Formatters
  71. template<typename manipulator>
  72. this_type& operator() (manipulator m) { return (stream_ << m, *this); }
  73. this_type& operator() (manipulator_type m) { return (m(stream_), *this); }
  74. this_type& operator() (std::locale const& l) { return (stream_.imbue(l), *this); }
  75. BOOST_CNV_PARAM(locale, std::locale) { return (stream_.imbue(arg[cnv::parameter::locale]), *this); }
  76. BOOST_CNV_PARAM(precision, int) { return (stream_.precision(arg[cnv::parameter::precision]), *this); }
  77. BOOST_CNV_PARAM(width, int) { return (stream_.width(arg[cnv::parameter::width]), *this); }
  78. BOOST_CNV_PARAM(fill, char) { return (stream_.fill(arg[cnv::parameter::fill]), *this); }
  79. BOOST_CNV_PARAM(uppercase, bool)
  80. {
  81. bool uppercase = arg[cnv::parameter::uppercase];
  82. uppercase ? (void) stream_.setf(std::ios::uppercase) : stream_.unsetf(std::ios::uppercase);
  83. return *this;
  84. }
  85. BOOST_CNV_PARAM(skipws, bool)
  86. {
  87. bool skipws = arg[cnv::parameter::skipws];
  88. skipws ? (void) stream_.setf(std::ios::skipws) : stream_.unsetf(std::ios::skipws);
  89. return *this;
  90. }
  91. BOOST_CNV_PARAM(adjust, boost::cnv::adjust)
  92. {
  93. cnv::adjust adjust = arg[cnv::parameter::adjust];
  94. /**/ if (adjust == cnv::adjust:: left) stream_.setf(std::ios::adjustfield, std::ios:: left);
  95. else if (adjust == cnv::adjust::right) stream_.setf(std::ios::adjustfield, std::ios::right);
  96. else BOOST_ASSERT(!"Not implemented");
  97. return *this;
  98. }
  99. BOOST_CNV_PARAM(base, boost::cnv::base)
  100. {
  101. cnv::base base = arg[cnv::parameter::base];
  102. /**/ if (base == cnv::base::dec) std::dec(stream_);
  103. else if (base == cnv::base::hex) std::hex(stream_);
  104. else if (base == cnv::base::oct) std::oct(stream_);
  105. else BOOST_ASSERT(!"Not implemented");
  106. return *this;
  107. }
  108. BOOST_CNV_PARAM(notation, boost::cnv::notation)
  109. {
  110. cnv::notation notation = arg[cnv::parameter::notation];
  111. /**/ if (notation == cnv::notation:: fixed) std::fixed(stream_);
  112. else if (notation == cnv::notation::scientific) std::scientific(stream_);
  113. else BOOST_ASSERT(!"Not implemented");
  114. return *this;
  115. }
  116. private:
  117. template<typename string_type, typename out_type> void str_to(cnv::range<string_type>, optional<out_type>&) const;
  118. template<typename string_type, typename in_type> void to_str(in_type const&, optional<string_type>&) const;
  119. mutable stream_type stream_;
  120. };
  121. template<typename char_type>
  122. template<typename string_type, typename in_type>
  123. inline
  124. void
  125. boost::cnv::basic_stream<char_type>::to_str(
  126. in_type const& value_in,
  127. boost::optional<string_type>& string_out) const
  128. {
  129. stream_.clear(); // Clear the flags
  130. stream_.str(stdstr_type()); // Clear/empty the content of the stream
  131. if (!(stream_ << value_in).fail())
  132. {
  133. buffer_type* buf = stream_.rdbuf();
  134. obuffer_type* obuf = reinterpret_cast<obuffer_type*>(buf);
  135. char_type const* beg = obuf->pbase();
  136. char_type const* end = obuf->pptr();
  137. string_out = string_type(beg, end); // Instead of stream_.str();
  138. }
  139. }
  140. template<typename char_type>
  141. template<typename string_type, typename out_type>
  142. inline
  143. void
  144. boost::cnv::basic_stream<char_type>::str_to(
  145. boost::cnv::range<string_type> string_in,
  146. boost::optional<out_type>& result_out) const
  147. {
  148. if (string_in.empty ()) return;
  149. istream_type& istream = stream_;
  150. buffer_type* oldbuf = istream.rdbuf();
  151. char_type const* beg = &*string_in.begin();
  152. std::size_t sz = string_in.end() - string_in.begin();
  153. ibuffer_type newbuf (beg, sz); //C02
  154. istream.rdbuf(&newbuf);
  155. istream.clear(); // Clear the flags
  156. istream >> *(result_out = boost::make_default<out_type>());
  157. if (istream.fail() || newbuf.gptr() != newbuf.egptr()/*C03*/)
  158. result_out = boost::none;
  159. istream.rdbuf(oldbuf);
  160. }
  161. #undef BOOST_CNV_STRING_ENABLE
  162. #undef BOOST_CNV_PARAM
  163. #endif // BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP