stream_translator.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // ----------------------------------------------------------------------------
  2. // Copyright (C) 2009 Sebastian Redl
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // For more information, see www.boost.org
  9. // ----------------------------------------------------------------------------
  10. #ifndef BOOST_PROPERTY_TREE_STREAM_TRANSLATOR_HPP_INCLUDED
  11. #define BOOST_PROPERTY_TREE_STREAM_TRANSLATOR_HPP_INCLUDED
  12. #include <boost/property_tree/ptree_fwd.hpp>
  13. #include <boost/optional/optional.hpp>
  14. #include <boost/optional/optional_io.hpp>
  15. #include <boost/core/enable_if.hpp>
  16. #include <boost/type_traits/decay.hpp>
  17. #include <boost/type_traits/integral_constant.hpp>
  18. #include <sstream>
  19. #include <string>
  20. #include <locale>
  21. #include <limits>
  22. namespace boost { namespace property_tree
  23. {
  24. template <typename Ch, typename Traits, typename E, typename Enabler = void>
  25. struct customize_stream
  26. {
  27. static void insert(std::basic_ostream<Ch, Traits>& s, const E& e) {
  28. s << e;
  29. }
  30. static void extract(std::basic_istream<Ch, Traits>& s, E& e) {
  31. s >> e;
  32. if(!s.eof()) {
  33. s >> std::ws;
  34. }
  35. }
  36. };
  37. // No whitespace skipping for single characters.
  38. template <typename Ch, typename Traits>
  39. struct customize_stream<Ch, Traits, Ch, void>
  40. {
  41. static void insert(std::basic_ostream<Ch, Traits>& s, Ch e) {
  42. s << e;
  43. }
  44. static void extract(std::basic_istream<Ch, Traits>& s, Ch& e) {
  45. s.unsetf(std::ios_base::skipws);
  46. s >> e;
  47. }
  48. };
  49. // Ugly workaround for numeric_traits that don't have members when not
  50. // specialized, e.g. MSVC.
  51. namespace detail
  52. {
  53. template <bool is_specialized>
  54. struct is_inexact_impl
  55. {
  56. template <typename T>
  57. struct test
  58. {
  59. typedef boost::false_type type;
  60. };
  61. };
  62. template <>
  63. struct is_inexact_impl<true>
  64. {
  65. template <typename T>
  66. struct test
  67. {
  68. typedef boost::integral_constant<bool,
  69. !std::numeric_limits<T>::is_exact> type;
  70. };
  71. };
  72. template <typename F>
  73. struct is_inexact
  74. {
  75. typedef typename boost::decay<F>::type decayed;
  76. typedef typename is_inexact_impl<
  77. std::numeric_limits<decayed>::is_specialized
  78. >::BOOST_NESTED_TEMPLATE test<decayed>::type type;
  79. static const bool value = type::value;
  80. };
  81. }
  82. template <typename Ch, typename Traits, typename F>
  83. struct customize_stream<Ch, Traits, F,
  84. typename boost::enable_if< detail::is_inexact<F> >::type
  85. >
  86. {
  87. static void insert(std::basic_ostream<Ch, Traits>& s, const F& e) {
  88. #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
  89. s.precision(std::numeric_limits<F>::max_digits10);
  90. #else
  91. s.precision(std::numeric_limits<F>::digits10 + 2);
  92. #endif
  93. s << e;
  94. }
  95. static void extract(std::basic_istream<Ch, Traits>& s, F& e) {
  96. s >> e;
  97. if(!s.eof()) {
  98. s >> std::ws;
  99. }
  100. }
  101. };
  102. template <typename Ch, typename Traits>
  103. struct customize_stream<Ch, Traits, bool, void>
  104. {
  105. static void insert(std::basic_ostream<Ch, Traits>& s, bool e) {
  106. s.setf(std::ios_base::boolalpha);
  107. s << e;
  108. }
  109. static void extract(std::basic_istream<Ch, Traits>& s, bool& e) {
  110. s >> e;
  111. if(s.fail()) {
  112. // Try again in word form.
  113. s.clear();
  114. s.setf(std::ios_base::boolalpha);
  115. s >> e;
  116. }
  117. if(!s.eof()) {
  118. s >> std::ws;
  119. }
  120. }
  121. };
  122. template <typename Ch, typename Traits>
  123. struct customize_stream<Ch, Traits, signed char, void>
  124. {
  125. static void insert(std::basic_ostream<Ch, Traits>& s, signed char e) {
  126. s << (int)e;
  127. }
  128. static void extract(std::basic_istream<Ch, Traits>& s, signed char& e) {
  129. int i;
  130. s >> i;
  131. // out of range?
  132. if(i > (std::numeric_limits<signed char>::max)() ||
  133. i < (std::numeric_limits<signed char>::min)())
  134. {
  135. s.clear(); // guarantees eof to be unset
  136. e = 0;
  137. s.setstate(std::ios_base::badbit);
  138. return;
  139. }
  140. e = (signed char)i;
  141. if(!s.eof()) {
  142. s >> std::ws;
  143. }
  144. }
  145. };
  146. template <typename Ch, typename Traits>
  147. struct customize_stream<Ch, Traits, unsigned char, void>
  148. {
  149. static void insert(std::basic_ostream<Ch, Traits>& s, unsigned char e) {
  150. s << (unsigned)e;
  151. }
  152. static void extract(std::basic_istream<Ch,Traits>& s, unsigned char& e){
  153. unsigned i;
  154. s >> i;
  155. // out of range?
  156. if(i > (std::numeric_limits<unsigned char>::max)()) {
  157. s.clear(); // guarantees eof to be unset
  158. e = 0;
  159. s.setstate(std::ios_base::badbit);
  160. return;
  161. }
  162. e = (unsigned char)i;
  163. if(!s.eof()) {
  164. s >> std::ws;
  165. }
  166. }
  167. };
  168. /// Implementation of Translator that uses the stream overloads.
  169. template <typename Ch, typename Traits, typename Alloc, typename E>
  170. class stream_translator
  171. {
  172. typedef customize_stream<Ch, Traits, E> customized;
  173. public:
  174. typedef std::basic_string<Ch, Traits, Alloc> internal_type;
  175. typedef E external_type;
  176. explicit stream_translator(std::locale loc = std::locale())
  177. : m_loc(loc)
  178. {}
  179. boost::optional<E> get_value(const internal_type &v) {
  180. std::basic_istringstream<Ch, Traits, Alloc> iss(v);
  181. iss.imbue(m_loc);
  182. E e;
  183. customized::extract(iss, e);
  184. if(iss.fail() || iss.bad() || iss.get() != Traits::eof()) {
  185. return boost::optional<E>();
  186. }
  187. return e;
  188. }
  189. boost::optional<internal_type> put_value(const E &v) {
  190. std::basic_ostringstream<Ch, Traits, Alloc> oss;
  191. oss.imbue(m_loc);
  192. customized::insert(oss, v);
  193. if(oss) {
  194. return oss.str();
  195. }
  196. return boost::optional<internal_type>();
  197. }
  198. private:
  199. std::locale m_loc;
  200. };
  201. // This is the default translator when basic_string is the internal type.
  202. // Unless the external type is also basic_string, in which case
  203. // id_translator takes over.
  204. template <typename Ch, typename Traits, typename Alloc, typename E>
  205. struct translator_between<std::basic_string<Ch, Traits, Alloc>, E>
  206. {
  207. typedef stream_translator<Ch, Traits, Alloc, E> type;
  208. };
  209. }}
  210. #endif