Line data Source code
1 : // Copyright Kevlin Henney, 2000-2005.
2 : // Copyright Alexander Nasonov, 2006-2010.
3 : // Copyright Antony Polukhin, 2011-2019.
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/type_traits/integral_constant.hpp>
34 : #include <boost/type_traits/type_identity.hpp>
35 : #include <boost/type_traits/conditional.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::conditional<
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::conditional<
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::conditional<
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::conditional<
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::conditional<
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::conditional<
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::conditional<
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::conditional<
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::conditional<
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::type_identity< char > {};
171 : template <> struct stream_char_common< boost::uint128_type >: public boost::type_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::conditional<
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::conditional<
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::conditional<
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::integral_constant<
431 : bool,
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::integral_constant<
438 : bool,
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 1782 : static inline bool try_convert(const Source& arg, Target& result) {
476 1782 : i_interpreter_type i_interpreter;
477 :
478 : // Disabling ADL, by directly specifying operators.
479 1782 : if (!(i_interpreter.operator <<(arg)))
480 : return false;
481 :
482 1782 : o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend());
483 :
484 : // Disabling ADL, by directly specifying operators.
485 1782 : if(!(out.operator >>(result)))
486 0 : 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 :
|