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