]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright Kevlin Henney, 2000-2005. |
2 | // Copyright Alexander Nasonov, 2006-2010. | |
3 | // Copyright Antony Polukhin, 2011-2014. | |
4 | // | |
5 | // Distributed under the Boost Software License, Version 1.0. (See | |
6 | // accompanying file LICENSE_1_0.txt or copy at | |
7 | // http://www.boost.org/LICENSE_1_0.txt) | |
8 | // | |
9 | // what: lexical_cast custom keyword cast | |
10 | // who: contributed by Kevlin Henney, | |
11 | // enhanced with contributions from Terje Slettebo, | |
12 | // with additional fixes and suggestions from Gennaro Prota, | |
13 | // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, | |
14 | // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, | |
15 | // Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters | |
16 | // when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014 | |
17 | ||
18 | #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP | |
19 | #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP | |
20 | ||
21 | #include <boost/config.hpp> | |
22 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
23 | # pragma once | |
24 | #endif | |
25 | ||
26 | #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) | |
27 | #define BOOST_LCAST_NO_WCHAR_T | |
28 | #endif | |
29 | ||
30 | #include <cstddef> | |
31 | #include <string> | |
32 | #include <boost/limits.hpp> | |
33 | #include <boost/mpl/bool.hpp> | |
34 | #include <boost/mpl/identity.hpp> | |
35 | #include <boost/mpl/if.hpp> | |
36 | #include <boost/type_traits/is_integral.hpp> | |
37 | #include <boost/type_traits/is_float.hpp> | |
38 | #include <boost/type_traits/has_left_shift.hpp> | |
39 | #include <boost/type_traits/has_right_shift.hpp> | |
40 | #include <boost/static_assert.hpp> | |
41 | #include <boost/detail/lcast_precision.hpp> | |
42 | ||
43 | #include <boost/lexical_cast/detail/widest_char.hpp> | |
44 | #include <boost/lexical_cast/detail/is_character.hpp> | |
45 | ||
46 | #ifndef BOOST_NO_CXX11_HDR_ARRAY | |
47 | #include <array> | |
48 | #endif | |
49 | ||
50 | #include <boost/array.hpp> | |
51 | #include <boost/range/iterator_range_core.hpp> | |
52 | #include <boost/container/container_fwd.hpp> | |
53 | ||
54 | #include <boost/lexical_cast/detail/converter_lexical_streams.hpp> | |
55 | ||
56 | namespace boost { | |
57 | ||
58 | namespace detail // normalize_single_byte_char<Char> | |
59 | { | |
60 | // Converts signed/unsigned char to char | |
61 | template < class Char > | |
62 | struct normalize_single_byte_char | |
63 | { | |
64 | typedef Char type; | |
65 | }; | |
66 | ||
67 | template <> | |
68 | struct normalize_single_byte_char< signed char > | |
69 | { | |
70 | typedef char type; | |
71 | }; | |
72 | ||
73 | template <> | |
74 | struct normalize_single_byte_char< unsigned char > | |
75 | { | |
76 | typedef char type; | |
77 | }; | |
78 | } | |
79 | ||
80 | namespace detail // deduce_character_type_later<T> | |
81 | { | |
82 | // Helper type, meaning that stram character for T must be deduced | |
83 | // at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) | |
84 | template < class T > struct deduce_character_type_later {}; | |
85 | } | |
86 | ||
87 | namespace detail // stream_char_common<T> | |
88 | { | |
89 | // Selectors to choose stream character type (common for Source and Target) | |
90 | // Returns one of char, wchar_t, char16_t, char32_t or deduce_character_type_later<T> types | |
91 | // Executed on Stage 1 (See deduce_source_char<T> and deduce_target_char<T>) | |
92 | template < typename Type > | |
93 | struct stream_char_common: public boost::mpl::if_c< | |
94 | boost::detail::is_character< Type >::value, | |
95 | Type, | |
96 | boost::detail::deduce_character_type_later< Type > | |
97 | > {}; | |
98 | ||
99 | template < typename Char > | |
100 | struct stream_char_common< Char* >: public boost::mpl::if_c< | |
101 | boost::detail::is_character< Char >::value, | |
102 | Char, | |
103 | boost::detail::deduce_character_type_later< Char* > | |
104 | > {}; | |
105 | ||
106 | template < typename Char > | |
107 | struct stream_char_common< const Char* >: public boost::mpl::if_c< | |
108 | boost::detail::is_character< Char >::value, | |
109 | Char, | |
110 | boost::detail::deduce_character_type_later< const Char* > | |
111 | > {}; | |
112 | ||
113 | template < typename Char > | |
114 | struct stream_char_common< boost::iterator_range< Char* > >: public boost::mpl::if_c< | |
115 | boost::detail::is_character< Char >::value, | |
116 | Char, | |
117 | boost::detail::deduce_character_type_later< boost::iterator_range< Char* > > | |
118 | > {}; | |
119 | ||
120 | template < typename Char > | |
121 | struct stream_char_common< boost::iterator_range< const Char* > >: public boost::mpl::if_c< | |
122 | boost::detail::is_character< Char >::value, | |
123 | Char, | |
124 | boost::detail::deduce_character_type_later< boost::iterator_range< const Char* > > | |
125 | > {}; | |
126 | ||
127 | template < class Char, class Traits, class Alloc > | |
128 | struct stream_char_common< std::basic_string< Char, Traits, Alloc > > | |
129 | { | |
130 | typedef Char type; | |
131 | }; | |
132 | ||
133 | template < class Char, class Traits, class Alloc > | |
134 | struct stream_char_common< boost::container::basic_string< Char, Traits, Alloc > > | |
135 | { | |
136 | typedef Char type; | |
137 | }; | |
138 | ||
139 | template < typename Char, std::size_t N > | |
140 | struct stream_char_common< boost::array< Char, N > >: public boost::mpl::if_c< | |
141 | boost::detail::is_character< Char >::value, | |
142 | Char, | |
143 | boost::detail::deduce_character_type_later< boost::array< Char, N > > | |
144 | > {}; | |
145 | ||
146 | template < typename Char, std::size_t N > | |
147 | struct stream_char_common< boost::array< const Char, N > >: public boost::mpl::if_c< | |
148 | boost::detail::is_character< Char >::value, | |
149 | Char, | |
150 | boost::detail::deduce_character_type_later< boost::array< const Char, N > > | |
151 | > {}; | |
152 | ||
153 | #ifndef BOOST_NO_CXX11_HDR_ARRAY | |
154 | template < typename Char, std::size_t N > | |
155 | struct stream_char_common< std::array<Char, N > >: public boost::mpl::if_c< | |
156 | boost::detail::is_character< Char >::value, | |
157 | Char, | |
158 | boost::detail::deduce_character_type_later< std::array< Char, N > > | |
159 | > {}; | |
160 | ||
161 | template < typename Char, std::size_t N > | |
162 | struct stream_char_common< std::array< const Char, N > >: public boost::mpl::if_c< | |
163 | boost::detail::is_character< Char >::value, | |
164 | Char, | |
165 | boost::detail::deduce_character_type_later< std::array< const Char, N > > | |
166 | > {}; | |
167 | #endif | |
168 | ||
169 | #ifdef BOOST_HAS_INT128 | |
170 | template <> struct stream_char_common< boost::int128_type >: public boost::mpl::identity< char > {}; | |
171 | template <> struct stream_char_common< boost::uint128_type >: public boost::mpl::identity< char > {}; | |
172 | #endif | |
173 | ||
174 | #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T) | |
175 | template <> | |
176 | struct stream_char_common< wchar_t > | |
177 | { | |
178 | typedef char type; | |
179 | }; | |
180 | #endif | |
181 | } | |
182 | ||
183 | namespace detail // deduce_source_char_impl<T> | |
184 | { | |
185 | // If type T is `deduce_character_type_later` type, then tries to deduce | |
186 | // character type using boost::has_left_shift<T> metafunction. | |
187 | // Otherwise supplied type T is a character type, that must be normalized | |
188 | // using normalize_single_byte_char<Char>. | |
189 | // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) | |
190 | template < class Char > | |
191 | struct deduce_source_char_impl | |
192 | { | |
193 | typedef BOOST_DEDUCED_TYPENAME boost::detail::normalize_single_byte_char< Char >::type type; | |
194 | }; | |
195 | ||
196 | template < class T > | |
197 | struct deduce_source_char_impl< deduce_character_type_later< T > > | |
198 | { | |
199 | typedef boost::has_left_shift< std::basic_ostream< char >, T > result_t; | |
200 | ||
201 | #if defined(BOOST_LCAST_NO_WCHAR_T) | |
202 | BOOST_STATIC_ASSERT_MSG((result_t::value), | |
203 | "Source type is not std::ostream`able and std::wostream`s are not supported by your STL implementation"); | |
204 | typedef char type; | |
205 | #else | |
206 | typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< | |
207 | result_t::value, char, wchar_t | |
208 | >::type type; | |
209 | ||
210 | BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_left_shift< std::basic_ostream< type >, T >::value), | |
211 | "Source type is neither std::ostream`able nor std::wostream`able"); | |
212 | #endif | |
213 | }; | |
214 | } | |
215 | ||
216 | namespace detail // deduce_target_char_impl<T> | |
217 | { | |
218 | // If type T is `deduce_character_type_later` type, then tries to deduce | |
219 | // character type using boost::has_right_shift<T> metafunction. | |
220 | // Otherwise supplied type T is a character type, that must be normalized | |
221 | // using normalize_single_byte_char<Char>. | |
222 | // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) | |
223 | template < class Char > | |
224 | struct deduce_target_char_impl | |
225 | { | |
226 | typedef BOOST_DEDUCED_TYPENAME normalize_single_byte_char< Char >::type type; | |
227 | }; | |
228 | ||
229 | template < class T > | |
230 | struct deduce_target_char_impl< deduce_character_type_later<T> > | |
231 | { | |
232 | typedef boost::has_right_shift<std::basic_istream<char>, T > result_t; | |
233 | ||
234 | #if defined(BOOST_LCAST_NO_WCHAR_T) | |
235 | BOOST_STATIC_ASSERT_MSG((result_t::value), | |
236 | "Target type is not std::istream`able and std::wistream`s are not supported by your STL implementation"); | |
237 | typedef char type; | |
238 | #else | |
239 | typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< | |
240 | result_t::value, char, wchar_t | |
241 | >::type type; | |
242 | ||
243 | BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value), | |
244 | "Target type is neither std::istream`able nor std::wistream`able"); | |
245 | #endif | |
246 | }; | |
247 | } | |
248 | ||
249 | namespace detail // deduce_target_char<T> and deduce_source_char<T> | |
250 | { | |
251 | // We deduce stream character types in two stages. | |
252 | // | |
253 | // Stage 1 is common for Target and Source. At Stage 1 we get | |
254 | // non normalized character type (may contain unsigned/signed char) | |
255 | // or deduce_character_type_later<T> where T is the original type. | |
256 | // Stage 1 is executed by stream_char_common<T> | |
257 | // | |
258 | // At Stage 2 we normalize character types or try to deduce character | |
259 | // type using metafunctions. | |
260 | // Stage 2 is executed by deduce_target_char_impl<T> and | |
261 | // deduce_source_char_impl<T> | |
262 | // | |
263 | // deduce_target_char<T> and deduce_source_char<T> functions combine | |
264 | // both stages | |
265 | ||
266 | template < class T > | |
267 | struct deduce_target_char | |
268 | { | |
269 | typedef BOOST_DEDUCED_TYPENAME stream_char_common< T >::type stage1_type; | |
270 | typedef BOOST_DEDUCED_TYPENAME deduce_target_char_impl< stage1_type >::type stage2_type; | |
271 | ||
272 | typedef stage2_type type; | |
273 | }; | |
274 | ||
275 | template < class T > | |
276 | struct deduce_source_char | |
277 | { | |
278 | typedef BOOST_DEDUCED_TYPENAME stream_char_common< T >::type stage1_type; | |
279 | typedef BOOST_DEDUCED_TYPENAME deduce_source_char_impl< stage1_type >::type stage2_type; | |
280 | ||
281 | typedef stage2_type type; | |
282 | }; | |
283 | } | |
284 | ||
285 | namespace detail // extract_char_traits template | |
286 | { | |
287 | // We are attempting to get char_traits<> from T | |
288 | // template parameter. Otherwise we'll be using std::char_traits<Char> | |
289 | template < class Char, class T > | |
290 | struct extract_char_traits | |
291 | : boost::false_type | |
292 | { | |
293 | typedef std::char_traits< Char > trait_t; | |
294 | }; | |
295 | ||
296 | template < class Char, class Traits, class Alloc > | |
297 | struct extract_char_traits< Char, std::basic_string< Char, Traits, Alloc > > | |
298 | : boost::true_type | |
299 | { | |
300 | typedef Traits trait_t; | |
301 | }; | |
302 | ||
303 | template < class Char, class Traits, class Alloc> | |
304 | struct extract_char_traits< Char, boost::container::basic_string< Char, Traits, Alloc > > | |
305 | : boost::true_type | |
306 | { | |
307 | typedef Traits trait_t; | |
308 | }; | |
309 | } | |
310 | ||
311 | namespace detail // array_to_pointer_decay<T> | |
312 | { | |
313 | template<class T> | |
314 | struct array_to_pointer_decay | |
315 | { | |
316 | typedef T type; | |
317 | }; | |
318 | ||
319 | template<class T, std::size_t N> | |
320 | struct array_to_pointer_decay<T[N]> | |
321 | { | |
322 | typedef const T * type; | |
323 | }; | |
324 | } | |
325 | ||
326 | namespace detail // lcast_src_length | |
327 | { | |
328 | // Return max. length of string representation of Source; | |
329 | template< class Source, // Source type of lexical_cast. | |
330 | class Enable = void // helper type | |
331 | > | |
332 | struct lcast_src_length | |
333 | { | |
334 | BOOST_STATIC_CONSTANT(std::size_t, value = 1); | |
335 | }; | |
336 | ||
337 | // Helper for integral types. | |
338 | // Notes on length calculation: | |
339 | // Max length for 32bit int with grouping "\1" and thousands_sep ',': | |
340 | // "-2,1,4,7,4,8,3,6,4,7" | |
341 | // ^ - is_signed | |
342 | // ^ - 1 digit not counted by digits10 | |
343 | // ^^^^^^^^^^^^^^^^^^ - digits10 * 2 | |
344 | // | |
345 | // Constant is_specialized is used instead of constant 1 | |
346 | // to prevent buffer overflow in a rare case when | |
347 | // <boost/limits.hpp> doesn't add missing specialization for | |
348 | // numeric_limits<T> for some integral type T. | |
349 | // When is_specialized is false, the whole expression is 0. | |
350 | template <class Source> | |
351 | struct lcast_src_length< | |
352 | Source, BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_integral<Source> >::type | |
353 | > | |
354 | { | |
355 | #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS | |
356 | BOOST_STATIC_CONSTANT(std::size_t, value = | |
357 | std::numeric_limits<Source>::is_signed + | |
358 | std::numeric_limits<Source>::is_specialized + /* == 1 */ | |
359 | std::numeric_limits<Source>::digits10 * 2 | |
360 | ); | |
361 | #else | |
362 | BOOST_STATIC_CONSTANT(std::size_t, value = 156); | |
363 | BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); | |
364 | #endif | |
365 | }; | |
366 | ||
367 | // Helper for floating point types. | |
368 | // -1.23456789e-123456 | |
369 | // ^ sign | |
370 | // ^ leading digit | |
371 | // ^ decimal point | |
372 | // ^^^^^^^^ lcast_precision<Source>::value | |
373 | // ^ "e" | |
374 | // ^ exponent sign | |
375 | // ^^^^^^ exponent (assumed 6 or less digits) | |
376 | // sign + leading digit + decimal point + "e" + exponent sign == 5 | |
377 | template<class Source> | |
378 | struct lcast_src_length< | |
379 | Source, BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_float<Source> >::type | |
380 | > | |
381 | { | |
382 | ||
383 | #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION | |
384 | BOOST_STATIC_ASSERT( | |
385 | std::numeric_limits<Source>::max_exponent10 <= 999999L && | |
386 | std::numeric_limits<Source>::min_exponent10 >= -999999L | |
387 | ); | |
388 | ||
389 | BOOST_STATIC_CONSTANT(std::size_t, value = | |
390 | 5 + lcast_precision<Source>::value + 6 | |
391 | ); | |
392 | #else // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION | |
393 | BOOST_STATIC_CONSTANT(std::size_t, value = 156); | |
394 | #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION | |
395 | }; | |
396 | } | |
397 | ||
398 | namespace detail // lexical_cast_stream_traits<Source, Target> | |
399 | { | |
400 | template <class Source, class Target> | |
401 | struct lexical_cast_stream_traits { | |
402 | typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<Source>::type src; | |
403 | typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<src>::type no_cv_src; | |
404 | ||
405 | typedef boost::detail::deduce_source_char<no_cv_src> deduce_src_char_metafunc; | |
406 | typedef BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::type src_char_t; | |
407 | typedef BOOST_DEDUCED_TYPENAME boost::detail::deduce_target_char<Target>::type target_char_t; | |
408 | ||
409 | typedef BOOST_DEDUCED_TYPENAME boost::detail::widest_char< | |
410 | target_char_t, src_char_t | |
411 | >::type char_type; | |
412 | ||
413 | #if !defined(BOOST_NO_CXX11_CHAR16_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS) | |
414 | BOOST_STATIC_ASSERT_MSG(( !boost::is_same<char16_t, src_char_t>::value | |
415 | && !boost::is_same<char16_t, target_char_t>::value), | |
416 | "Your compiler does not have full support for char16_t" ); | |
417 | #endif | |
418 | #if !defined(BOOST_NO_CXX11_CHAR32_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS) | |
419 | BOOST_STATIC_ASSERT_MSG(( !boost::is_same<char32_t, src_char_t>::value | |
420 | && !boost::is_same<char32_t, target_char_t>::value), | |
421 | "Your compiler does not have full support for char32_t" ); | |
422 | #endif | |
423 | ||
424 | typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< | |
425 | boost::detail::extract_char_traits<char_type, Target>::value, | |
426 | BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits<char_type, Target>, | |
427 | BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits<char_type, no_cv_src> | |
428 | >::type::trait_t traits; | |
429 | ||
430 | typedef boost::mpl::bool_ | |
431 | < | |
432 | boost::is_same<char, src_char_t>::value && // source is not a wide character based type | |
433 | (sizeof(char) != sizeof(target_char_t)) && // target type is based on wide character | |
434 | (!(boost::detail::is_character<no_cv_src>::value)) | |
435 | > is_string_widening_required_t; | |
436 | ||
437 | typedef boost::mpl::bool_ | |
438 | < | |
439 | !(boost::is_integral<no_cv_src>::value || | |
440 | boost::detail::is_character< | |
441 | BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::stage1_type // if we did not get character type at stage1 | |
442 | >::value // then we have no optimization for that type | |
443 | ) | |
444 | > is_source_input_not_optimized_t; | |
445 | ||
446 | // If we have an optimized conversion for | |
447 | // Source, we do not need to construct stringbuf. | |
448 | BOOST_STATIC_CONSTANT(bool, requires_stringbuf = | |
449 | (is_string_widening_required_t::value || is_source_input_not_optimized_t::value) | |
450 | ); | |
451 | ||
452 | typedef boost::detail::lcast_src_length<no_cv_src> len_t; | |
453 | }; | |
454 | } | |
455 | ||
456 | namespace detail | |
457 | { | |
458 | template<typename Target, typename Source> | |
459 | struct lexical_converter_impl | |
460 | { | |
461 | typedef lexical_cast_stream_traits<Source, Target> stream_trait; | |
462 | ||
463 | typedef detail::lexical_istream_limited_src< | |
464 | BOOST_DEDUCED_TYPENAME stream_trait::char_type, | |
465 | BOOST_DEDUCED_TYPENAME stream_trait::traits, | |
466 | stream_trait::requires_stringbuf, | |
467 | stream_trait::len_t::value + 1 | |
468 | > i_interpreter_type; | |
469 | ||
470 | typedef detail::lexical_ostream_limited_src< | |
471 | BOOST_DEDUCED_TYPENAME stream_trait::char_type, | |
472 | BOOST_DEDUCED_TYPENAME stream_trait::traits | |
473 | > o_interpreter_type; | |
474 | ||
475 | static inline bool try_convert(const Source& arg, Target& result) { | |
476 | i_interpreter_type i_interpreter; | |
477 | ||
478 | // Disabling ADL, by directly specifying operators. | |
479 | if (!(i_interpreter.operator <<(arg))) | |
480 | return false; | |
481 | ||
482 | o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend()); | |
483 | ||
484 | // Disabling ADL, by directly specifying operators. | |
485 | if(!(out.operator >>(result))) | |
486 | return false; | |
487 | ||
488 | return true; | |
489 | } | |
490 | }; | |
491 | } | |
492 | ||
493 | } // namespace boost | |
494 | ||
495 | #undef BOOST_LCAST_NO_WCHAR_T | |
496 | ||
497 | #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP | |
498 |