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